<?

class phrowser
{
	/**
	 * Properties
	 */
	protected $body = '';
	protected $headers = array();
	protected $cookies = array();

	/**
	 * Default settings
	 */
	protected $preserve_cookies = true;
	protected $defaul_options = array(
		CURLOPT_FOLLOWLOCATION => true
	);

	public function  __construct()
	{
		if ( !function_exists('curl_init') )
		{
			throw new Exception('cURL PHP library is required for this class, please install it');
		}
	}

	/**
	 * Set cURL option
	 */
	public function set_option( $curl_option, $value )
	{
		$this->defaul_options[$curl_option] = $value;
	}

	/**
	 * Send GET request to URL
	 */
	public function url_get( $url )
	{
		$this->exec_url($url);
	}

	/**
	 * Send POST request to URL
	 */
	public function url_post( $url, $variables = array() )
	{
		foreach ( $variables as $var => $value )
		{
			$post_vars[] = "{$var}=" . urlencode($value);
		}

		$this->exec_url($url, array(
			CURLOPT_POST => true,
			CURLOPT_POSTFIELDS => implode('&', $post_vars)
		));
	}

	/**
	 * Returns last response body
	 */
	public function get_body()
	{
		return $this->body;
	}

	/**
	 * Returns last response headers array
	 */
	public function get_headers()
	{
		return $this->headers;
	}

	/**
	 * Returns last response cookies array
	 */
	public function get_cookies()
	{
		return $this->cookies;
	}

	/**
	 * Returns last response cookie by name
	 */
	public function get_cookie( $name )
	{
		return $this->cookies[$name]['value'];
	}

	/**
	 * Sets cookie
	 */
	public function set_cookie( $name, $value )
	{
		$this->cookies[$name] = array('value' => $value);
	}

	/**
	 * Find one match by pcre pattern in last response
	 * Only one capturing group must be defined!
	 *
	 * Example (Finds some image source on page):
	 * $b->find_scalar_match('/<img src="([^"]+)"\/>/');
	 * 
	 */
	public function find_scalar_match( $pattern )
	{
		preg_match($pattern, $this->get_body(), $matches);

		return @$matches[1];
	}

	/**
	 * Find all matches by pcre pattern in last response
	 * At least one capturing group must be defined
	 * Returns an array of resulted matches
	 *
	 */
	public function find_all_matches( $pattern )
	{
		preg_match_all($pattern, $this->get_body(), $matches);
		array_shift($matches);

		$result = array();
		if ( $matches[0] )
		{
			foreach ( $matches[0] as $i => $match ) foreach ( $matches as $j => $match )
			{
				$result[$i][$j] = $match[$i];
			}
		}

		return $result;
	}

	protected function exec_url( $url, $options = array() )
	{
		$options[CURLOPT_RETURNTRANSFER] = true;
		$options[CURLOPT_HEADER] = true;
		$options[CURLOPT_USERAGENT] = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042523 Ubuntu/8.10 (intrepid) Firefox/3.0.10 GTB5';
		$options[CURLOPT_REFERER] = $url;

		foreach ( $this->defaul_options as $k => $v )
		{
			if ( !array_key_exists($k, $options) )
			$options[$k] = $v;
		}
		
		if ( $this->preserve_cookies && $this->cookies )
		{
			$cookies = array();
			
			foreach ( $this->cookies as $cookie_name => $cookie_data )
			{
				$cookies[] = "{$cookie_name}={$cookie_data[value]}";
			}
			
			$options[CURLOPT_COOKIE] = implode(';', $cookies);
		}

		$c = curl_init( $url );

		foreach ( $options as $opt => $val )
		{
			curl_setopt($c, $opt, $val);
		}

		$data = curl_exec($c);
		curl_close($c);

		$this->parse_response($data);
	}

	protected function parse_response( $http )
	{
		while ( strpos($http, 'HTTP') === 0 )
		{
			$header_divider = strpos($http, "\r\n\r\n");
			$this->body = substr($http, $header_divider + 4);
			$this->headers = $this->parse_headers( substr($http, 0, $header_divider) );

			$http = $this->body;
		}

		if ( array_key_exists('Content-Type', $this->headers) && strpos($this->headers['Content-Type'], 'charset=') )
		{
			if ( ( $charset = substr($this->headers['Content-Type'], strpos($this->headers['Content-Type'], 'charset=') + 8) ) != 'UTF-8' )
			{
				$this->body = iconv($charset, 'UTF-8', $this->body);
			}
		}
		else if ( $charset = $this->find_scalar_match('/text\/html; charset=([^"]+)"/') )
		{
			$this->body = iconv($charset, 'UTF-8', $this->body);
		}
	}

	protected function parse_headers( $http )
	{
		$headers = array();

		if ( $http_lines = explode("\r\n", $http) )
		{
			foreach ( $http_lines as $line )
			{
				$header = explode(':', $line);
				if ( $headers[$header[0]] )
				{
					$headers[$header[0]] = (array)$headers[$header[0]];
					$headers[$header[0]][] = $header[1];
				}
				else
				{
					if ( $header[0] == 'Location' )
					{
						$headers[$header[0]] = implode(':', array_slice($header, 1));
					}
					else
					{
						$headers[$header[0]] = $header[1];
					}
				}
			}
		}

		if ( $headers['Set-Cookie'] )
		{
			$this->parse_cookies($headers);
		}
		
		return $headers;
	}

	protected function parse_cookies( $headers )
	{
		if ( $cookie_headers = (array)$headers['Set-Cookie'] )
		{
			foreach ( $cookie_headers as $cookie_header )
			{
				$cookie_data = explode(';', $cookie_header);
				$cookie_val = array_shift($cookie_data);
				$cookie_val = explode('=', $cookie_val);
				
				$cookie_params = array();
				foreach ( $cookie_data as $cookie_param )
				{
					$cookie_param = explode('=', $cookie_param);
					$cookie_params[trim($cookie_param[0])] = $cookie_param[1];
				}

				$cookie_params['value'] = $cookie_val[1];
				
				$this->cookies[trim($cookie_val[0])] = $cookie_params;
			}
		}
	}
}
